package com.cdream.basic.thread.pattern;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import static java.nio.charset.StandardCharsets.UTF_8;

/**
 * @author cdream
 * @date 2022/2/9
 */
@Slf4j
public class GuardedObjectExample {
    public static void main(String[] args) {
        // GuardedObject go = new GuardedObject(1);
        // new Thread(() -> {
        //     Object o = go.get(1000);
        //     log.debug(o.toString());
        //
        // }, "t1").start();
        // new Thread(() -> {
        //     go.complete(download());
        // }, "t2").start();
    }

    @SneakyThrows
    public static List<String> download() {
        HttpURLConnection con = (HttpURLConnection) new URL("https://www.baidu.com/").openConnection();
        List<String> lines = new ArrayList<>();
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(con.getInputStream(), UTF_8))) {
            String line;
            while ((line = reader.readLine()) != null) {
                lines.add(line);
            }
        }
        return lines;
    }
}
@Slf4j(topic = "people")
class People extends Thread{
    @Override
    public void run() {
        GuardedObject go = Mailboxes.createGuardedObject();
        log.debug("开始收信id:{}",go.getId());
        Object mail = go.get(5000);
        log.debug("收信id:{},内容:{}",go.getId(),mail);
    }
}
@Slf4j(topic = "postman")
class Postman extends Thread{
    private int id;
    private String mail;

    public Postman(int id, String mail) {
        this.id = id;
        this.mail = mail;
    }

    @Override
    public void run() {
        GuardedObject guardedObject = Mailboxes.getGuardedObject(id);
        guardedObject.complete(mail);
    }
}

class Mailboxes {
    private static Map<Integer, GuardedObject> boxes = new ConcurrentHashMap<>();

    private static int id = 1;

    public static GuardedObject createGuardedObject() {
        GuardedObject go = new GuardedObject(createId());
        boxes.put(go.getId(), go);
        return go;
    }

    private static int createId() {
        synchronized (Mailboxes.class) {
            return id++;
        }
    }
    public static Set<Integer> getIds(){
        return boxes.keySet();
    }
    public static GuardedObject getGuardedObject(int id){
        return boxes.remove(id);
    }
}

class GuardedObject {
    private int id;
    private Object response;

    public GuardedObject(int id) {
        this.id = id;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public Object get(long timeout) {
        synchronized (this) {
            long begin = System.currentTimeMillis();
            // 经历的时间
            long pass = 0;
            while (response == null) {
                if (pass >= timeout) {
                    break;
                }
                try {
                    this.wait(timeout - pass);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                pass = System.currentTimeMillis() - begin;
            }
        }
        return response;
    }

    public void complete(Object response) {
        synchronized (this) {
            this.response = response;
            this.notifyAll();
        }
    }
}
